import SerialPort from 'serialport'
import { Context } from 'koa';
const cp = require('child_process').execFile
import { logger } from "../until/log"
import websocketIo from "../until/websocket.io";
import {DelimiterParser} from '@serialport/parser-delimiter'
import eventEmit from "../until/emitEvent";
import DataService from '../service/Admin/Data.service'
import {ByteLengthParser} from '@serialport/parser-byte-length'
import { Transform } from 'stream'
import CommandQueue from '../until/CommandQueue';
import config from '../../config'
// 问题原因是找不到 'threads' 模块及其类型声明，需要安装该模块
import { spawn, Thread, Worker} from 'threads'
import { command } from '../until/AtCommand';
import TcpClient from '../until/Tcp';

// 解析16进制数据为浮点数
function hexToFloat(hexString) {
    // 创建一个包含4个字节的Buffer对象，用于存储IEEE 754格式的32位浮点数
    //@ts-ignore
    let buffer = Buffer.from(hexString, 'hex');
    // 使用readFloatBE方法读取大端序的32位浮点数
    return buffer.readFloatBE(0).toFixed(2);
}
function createData(str: string) {
    let id = str.slice(1,2)
    let uvc = hexToFloat(str.substring(2,10))
    let tem = hexToFloat(str.substring(10,18))
    let hum = hexToFloat(str.substring(18,str.length))
    return {
        ID: Number(id),
        data: [Number(uvc),0,Number(tem),Number(hum),0],
        sta: [0,0,0,0,0]
    }
}

interface IData {
  ID: number;
  data: number[];
  sta: number[];
}

// 自定义数据包解析器
class PacketParser extends Transform {
    private buffer: Buffer = Buffer.alloc(0);
    private readonly HEADER = Buffer.from([0xf7, 0xf7]);
    private readonly FOOTER = Buffer.from([0x7f, 0x7f]);

    _transform(chunk: Buffer, encoding: string, callback: Function) {
        // 将新数据添加到缓冲区
        this.buffer = Buffer.concat([this.buffer, chunk]);
        // 查找数据包
        while (this.buffer.length >= 4) { // 至少需要帧头和帧尾的长度
            // 查找帧头
            const headerIndex = this.buffer.indexOf(this.HEADER);
            if (headerIndex === -1) {
                // 没有找到帧头，清空缓冲区
                this.buffer = Buffer.alloc(0);
                break;
            }

            // 从帧头开始查找帧尾
            const searchStart = headerIndex + 2; // 跳过帧头
            const footerIndex = this.buffer.indexOf(this.FOOTER, searchStart);
            
            if (footerIndex === -1) {
                // 没有找到帧尾，保留从帧头开始的数据
                this.buffer = this.buffer.slice(headerIndex);
                break;
            }

            // 提取完整的数据包
            const packetLength = footerIndex + 2 - headerIndex; // 包含帧尾的长度
            const packet = this.buffer.slice(headerIndex, headerIndex + packetLength);
            
            // 发送数据包
            this.push(packet);
            
            // 更新缓冲区，移除已处理的数据
            this.buffer = this.buffer.slice(headerIndex + packetLength);
        }
        
        callback();
    }
}

class SocketController {
    public serialName;
    static serialport:SerialPort;
    public baudRate:number; // 波特率
    static localData:any;
    static isOpenSerial:boolean = false; // 是否打开了串口
    static receiveTime = new Date().getTime(); // 获取接收的时间戳
    static timer:any;
    public threadList: Thread[] = []; // 线程池
    public threadNum: number = 5
    public currentThreadId: number = 1
    public parity: any;
    private commandQueue: CommandQueue;
    constructor() {
        this.commandQueue = CommandQueue.getInstance();
        // 监听网关发送的数据
        eventEmit.on('receiveData',(data) => {
            // 使用优先级1发送命令（高优先级）
            if (config.method === "485通信") {
                this.commandQueue.addCommand(data, 1);
                
            } else {
                TcpClient.getInstance().socket.write(data);
            }
        });

        // 监听命令队列的发送事件
        this.commandQueue.onSendCommand((data) => {
            if (SocketController.serialport && SocketController.isOpenSerial) {
                SocketController.serialport.write(data, "ascii", (err) => {
                    if (err) {
                        logger.error("写入失败:", err);
                        // 如果写入失败，可以在这里添加重试逻辑
                    }
                });
            }
        });
    }
    // 连接串口
    async connectionSerialport(serialName,baudRate:number,parity: any) {
        this.parity = parity
        this.serialName = serialName
        this.baudRate = baudRate
        // for(let i=0;i<this.threadNum;i++) {
        //     const threads = await spawn(new Worker('../until/index'))
        //     this.threadList.push(threads)
        // }
  
        // @ts-ignore
        SocketController.serialport = new SerialPort(serialName,{
                baudRate,
                dataBits: 8,
                parity,
                stopBits: 1,
            },(err) => {
                if (err) {
                    logger.warn("串口连接失败：" + err)
                    return
                }
                console.log("串口连接成功")
                SocketController.isOpenSerial = true
                SocketController.serialport.on("open",() => {
                    console.log("打开成功")
                })
                
                // 使用自定义数据包解析器
                const parser = SocketController.serialport.pipe(new PacketParser());
                parser.on('data', (packet) => { 
                    // 移除帧头和帧尾，获取实际数据
                    const data = packet.slice(2, -2);
                    try {
                        // 解析数据包内容
                        const parsedData = this.parsePacketData(data);
                        if (parsedData) {
                            // 记录设备数据接收，用于设备在线状态管理
                            // 串口连接的设备使用本地网关标识
                            websocketIo.getInstance.recordDeviceData(parsedData.ID.toString(), 'localhost');
                            
                            this.saveData(parsedData);
                            websocketIo.getInstance.socketObj.send(JSON.stringify({action: 'sendData',...parsedData, gatewayIp: 'localhost'}))
                        }
                    } catch (error) {
                        logger.error('Error parsing packet:', error);
                    }
                });

                SocketController.serialport.on("error", (err) => {
                    logger.error('Serial port error:', err);
                    // 发生错误时清空命令队列
                    this.commandQueue.clearQueue();
                });

                SocketController.serialport.on("data",(buffer) => {
                    if (buffer[0] !== 0xf7 || buffer[1] !== 0xf7) {
                        console.log("接收到其他的AT指令")
                        let at = buffer.toString("ascii")
                        if (at.includes("FF")) {
                        let deviceList: Array<Record<string,any>> = at.trim().split("\r\n").map(device => {
                            let obj = device.split(',')
                            return {
                                deviceId: obj[1],
                                deviceESN: obj[0],
                                deviceStatus: obj[2],
                            }
                        })
                         if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({action: "gateway", type: "queryAll", devices: deviceList}));

                        } else if (at.includes("AT+ATCMD") && at.includes("AT+VER")) {
                           if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({action: "gateway", type: "queryVersion",message: at}));
                            
                        } else if (at.includes("ok") || at.includes("OK") || at.includes("ERROR") || at.includes("error")) {
                            const resultMessage = (at.includes("ok") || at.includes("OK")) ? "OK" : "ERROR";
                            if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({action: "gateway", type: "common", message: resultMessage}));
                        } else if (at.includes("AT+ATCMD") && at.includes("AT+DTYPE")) {
                           if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({action: "gateway", type: "queryDeviceType",message: at}));
                        } else if (at.includes("AT+CELLID")) {
                           if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({action: "gateway", type: "queryGateway",message: at}));
                        } else if (at.include("AT+GAIN?")) {
                           if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({action: "gateway", type: "queryCircuitGain",message: at}));
                        } 
                    }
                })
        })
    }

    // 解析数据包内容
    private parsePacketData(data: Buffer): IData | null {
          const statusValues: number[] = [];
        try {
            // 数据包格式：
            // [帧头(2字节)][ID(1字节)][功能码(1字节)][数据长度(1字节)][数据(N字节)][状态(2字节)][帧尾(2字节)]
            if (data.length < 5) { // 至少需要5字节（ID + 功能码 + 数据长度）
                return null;
            }

            const id = data[0];  // 设备ID
            const funcCode = data[1];  // 功能码
            const dataLength = data[2];  // 数据长度
            // 检查数据长度是否合理
            if (data.length < 3 + dataLength) {
                return null;
            }

            // 解析数据部分
            const dataValues: number[] = [];  // 改回number类型
            for (let i = 0; i < dataLength; i += 2) {
                if (i + 1 < dataLength) {
                    // 将两个字节组合成一个值
                    const value = (data[3 + i] << 8) | data[3 + i + 1];
                    // 判断是否是最后一个值（紫外整数）
                    if (eventEmit.type !== "ten") {
                        const isLastValue = i + 3 > dataLength - 1;
                        if (isLastValue) {
                            dataValues.push(value);  // 紫外整数保持原值
                        } else {
                            dataValues.push(parseFloat((value / 100).toFixed(2)));  // 其他值除以100并保持两位小数
                        }
                        statusValues.push(0);} else {
                        if (i < 8) {
                            dataValues.push(parseFloat((value / 100).toFixed(2)));  // 其他值除以100并保持两位小数
                        } else {
                            dataValues.push(value);  // 紫外整数保持原值
                        }
                    }
                }
            }

            // 解析状态部分（最后两个字节）
            return {
                ID: id,
                data: dataValues,
                sta: [0,0,0,0,0]
            };
        } catch (error) {
            logger.error('Error parsing packet data:', error);
            return null;
        }
    }

    public async saveData(data:IData) {
        const savePromise = [
            DataService.saveDataList({
                module_id: data.ID,
                uvc: data.data[0],
                inf: data.data[1],
                tem: data.data[2],
                hum: data.data[3],
                pre: data.data[4]
            }),
            // 存储设备状态
            // DataService.saveStatusList({
            //     module_id: data.ID,
            //     uvc_sta: data.sta[0],
            //     ir_sta: data.sta[1],
            //     temp_sta: data.sta[2],
            //     hum_sta: data.sta[3],
            //     pre_sta: data.sta[4]
            // })
        ]
        try {
            await Promise.all(savePromise)
        } catch {
            console.log('存储失败')
        }
    }

    static isSend() {
     return new Promise((resolve => {
         let sendTime = new Date().getTime()  // 获取发送的时间
         let spaceTime = sendTime - SocketController.receiveTime // 获取发送和接收的时间间隔
         if (spaceTime > 200 && spaceTime < 800) {
              resolve(true)
         } else {
             console.log("相撞了")
              resolve(false)
         }
     }))
    }
    // 获取串口数据
    getSerialPort(ctx:Context){
        if (SocketController.isOpenSerial) {
            ctx.body = {
                code: 200,
                msg: "获取串口数据成功",
                data: SocketController.localData
               }
        } else {
            ctx.body = {
                code: 304,
                msg: "还没有打开串口"
            }
        }
    }
    async changeSerialPort(ctx:any) {
        let varNameList = ['uv','inf',"acc",'tem','hum','pre'] // 定义一个变量的数组
        let id = ctx.request.body.id
        let device_id = ctx.request.body.device_id // 设备的id
        let alarm = ctx.request.body.currentValue
         let obj = {
             ID: device_id,
             [varNameList[id - 1]]: {alarm:[alarm]}
         }
        try {
           let bool = await SocketController.isSend()
            if (bool) {
                let bool = await SocketController.serialport.write(JSON.stringify(obj).trim())
            } else {
                setTimeout(() => {
                    SocketController.serialport.write(JSON.stringify(obj).trim(),(err) => {
                        if (err) return console.log("写入失败")
                    })
                },200)
            }
        } catch(err) {
            logger.error("修改阈值失败" + err)
            ctx.body = {code: 500,msg:"修改阈值失败，查看设备连接"}
        }
            ctx.body = {
                code: 200,
                msg: "修改成功",
                data: obj
            }
    }
    async changeSpeed(ctx:any) {
        // 改变数据采样的速率
        let bool = await SocketController.isSend()
        let speed = ctx.request.body.speed
        if (bool) {
            await SocketController.serialport.write(`{DELAY:[${speed}]}`,(err) => {
                if (err) return ctx.body = {code: 500,msg: "修改失败"}
            })
            ctx.body = {code: 200,msg: "修改速率成功"}
        } else {
            setTimeout(() => {
                SocketController.serialport.write(`{DELAY:[${speed}]}`,(err) => {
                    if (err) return ctx.body = {code: 500,msg: "修改失败"}
                })
            },200)
            ctx.body = {code: 200,msg: "修改速率成功"}
        }
    }
    // 获取模块的个数
    async getModuleNum(ctx:Context) {
        ctx.body = {
            code: 200,
            msg: "获取模块的个数成功",
            data: {
                moduleNum: eventEmit.moduleNum,
                uv: config.uv,
                inf: config.inf,
                other: config.other
            }
        }
    }
}

export default new SocketController
